package com.jingdianjichi.gateway.exception;

import cn.dev33.satoken.exception.SaTokenException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jingdianjichi.gateway.entity.Result;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 网关全局异常处理,之前单体的是不行的这里,这里是网关的写法
 */
@Component
public class GateWayExceptionHandler implements ErrorWebExceptionHandler {
    //该类实现了 ErrorWebExceptionHandler 接口，这是 Spring WebFlux 提供的一个用于处理 Web 异常的接口。

    //序列化工具
    private ObjectMapper objectMapper=new ObjectMapper();

    /**
     *serverWebExchange把所有的req和resp都放进啦,throwable就是异常了
     */
    @Override
    public Mono<Void> handle(ServerWebExchange serverWebExchange, Throwable throwable) {
        ServerHttpRequest request = serverWebExchange.getRequest();
        ServerHttpResponse response = serverWebExchange.getResponse();

        Integer code=200;
        String message="";

        if (throwable instanceof SaTokenException)
        {
            code=401;
            message="用户无权限";
        }else
        {
            code=500;
            message="系统繁忙";
        }

        Result result = Result.fail(code, message);

        //设置响应头
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);

        //这个Mono.fromSupplier()就是执行你里面写的代码 生成响应体:
        return response.writeWith(Mono.fromSupplier(() ->{
            DataBufferFactory dataBufferFactory = response.bufferFactory();
            /*
                ataBuffer 是一个用于管理数据的对象，特别适用于处理流式数据，比如在处理 HTTP 响应时。
                    /它可以用于将数据分块处理，以提高内存效率和性能。
             */
            byte[] bytes =null;

            try {
                 bytes= objectMapper.writeValueAsBytes(result);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }

            DataBuffer wrap = dataBufferFactory.wrap(bytes);
            /*
                由于它是针对流式数据设计的，DataBuffer 可以在性能上进行优化。例如，通过复用内存或直接与操作系统的内存管理接口交互，可以减少数据拷贝和复制的开销。
                    所以我们转换为DataBuffer这个对象
             */

            return wrap;
        }));
    }

    /*
        Mono<Void> 是 Project Reactor 库的一部分，通常用于响应式编程环境中，特别是在 Spring WebFlux 中。在这个上下文里，Mono<Void> 的作用如下：
            1. 定义异步操作
            Mono 是 Reactor 中的一个反应式类型，表示在未来某个时间点将会有零个或一个元素的结果。它可以理解为一个异步的计算过程。
            Void 表示这个 Mono 不会返回任何具体的值。当操作完成时，它只是表明操作已经成功执行，而不需要返回任何数据。
            2. 用于响应处理
            在 WebFlux 中，Mono<Void> 通常用于处理 HTTP 请求的响应，尤其是在需要执行某个操作但不需要返回响应体的场景。例如，常见的用例包括：

            完成一个请求处理而没有返回数据（如 DELETE 请求）。
            处理一个需要异步完成的操作，比如保存数据到数据库或发送消息到消息队列。
            3. 保持非阻塞行为
            返回 Mono<Void> 可以确保操作是非阻塞的。在响��式编程中，调用代码可以在等待操作完成时继续执行其他任务，提升应用的性能和响应能力。

            4. 错误处理
            Mono 也可以��理错误。如果在执行操作时抛出异常，可以通过 onError 的方式进行处理。这使得错误处理更加灵活和可控。
     */
}
